import { ref, computed, onMounted, onUnmounted, type Ref, watch } from 'vue'

interface Options {
  containerRef: Ref<HTMLElement | undefined>
  itemHeight: number
  overscan?: number
}

export function useVirtualList<T = any>(list: Ref<T[]>, options: Options) {
  const { containerRef, itemHeight, overscan = 2 } = options
  const scrollTop = ref(0)
  const containerHeight = ref(0)
  const safeList = ref(Array.from(list.value))
  watch(list, (newList) => {
    safeList.value = Array.isArray(newList) ? newList : []
  })

  const range = computed(() => {
    const start = Math.max(0, Math.floor(scrollTop.value / itemHeight) - overscan)
    const end = Math.min(
      safeList.value.length - 1,
      // 每次传的数据递增,所以safeList递增,不能以常规虚拟列表做
      // Math.ceil((scrollTop.value + containerHeight.value) / itemHeight) + overscan,
    )
    return { start, end }
  })

  const visibleData = computed(() => {
    return safeList.value.slice(range.value.start, range.value.end + 1)
  })

  const totalHeight = computed(() => itemHeight * safeList.value.length)

  // 偏移量（用于占位）
  const offset = computed(() => range.value.start * itemHeight)

  //把多次事件合并到一帧，但不会减少事件触发的频率
  //继续优化可以结合 Intersection Observer 只在首尾哨兵进入视口时才加载更多数据
  let locking = false
  const handleScroll = () => {
    console.log(range.value)

    if (!locking) {
      locking = true
      requestAnimationFrame(() => {
        if (containerRef.value) {
          scrollTop.value = containerRef.value.scrollTop
        }
        locking = false
      })
    }
  }

  const updateContainerSize = () => {
    if (containerRef.value) {
      containerHeight.value = containerRef.value.clientHeight
    }
  }

  onMounted(() => {
    updateContainerSize()
    containerRef.value?.addEventListener('scroll', handleScroll)
  })

  onUnmounted(() => {
    containerRef.value?.removeEventListener('scroll', handleScroll)
  })

  return {
    visibleData,
    totalHeight,
    offset,
  }
}
